﻿const run = require('./db-context').runSp;
const assmType = require('./db-context').AssemblyType;
const SQLTypes = require('tedious').TYPES;
const uuidv1 = require('uuid/v1');

const paraEno = eno => ({ name: 'eno', type: SQLTypes.VarChar, value: eno });

/* This function constructs the tree view graph of departments and employees  
 */
function assembleStaffGraph(departments, teachers, teacherBuilder) {
    let { deps, secs } = assembleContainers(departments);
    attachTeachers(deps, secs, teachers);
    return deps;
    function assembleContainers(departments) {
        // to seperate departments(处) and sections(科) from mixed data
        var deps = [], secs = [];
        departments.forEach(d => {
            if (!d.pno) {   // if a node's parent's No. is null, the node is department
                deps.push({ dno: d.dno, name: d.name });
            } else {        // if the No. of a node's parent is not null, the node is a section
                secs.push(d);
            }
        });
        // build hirachical graph
        var newSecs = [];
        deps.forEach(d => {
            let dno = d.dno,
                children = secs.filter(s => s.pno === dno),
                sections = children && children.map(({ dno, name }) => ({ dno, name }));   // remove pno property
            if (sections && sections.length > 0) {
                d.sections = sections;
                newSecs = newSecs.concat(sections);
            }
        })
        return {
            deps,
            secs: newSecs
        };
    }
    function attachTeachers(deps, secs, teachers) {
        teachers.forEach(e => {
            let { dno } = e;
            let org = deps.find(d => d.dno === dno) || secs.find(d => d.dno === dno);
            if (org) {
                if (!Array.isArray(org.teachers)) org.teachers = [];
                org.teachers.push(teacherBuilder(e));
            }
        })
    }
}

const sysLoad = async (eno) => {
    // basic: {collegeName,eno,name,isApprover,isOrgMan}
    // grantablePerms:[{name,bit},...]
    console.log("request system load!!!!");
    console.log(paraEno(eno));
    var [basic = null, grantablePerms = null] = await run('humanSysLoad', [paraEno(eno)]);
    console.log(basic, grantablePerms);
    return;
    if (basic) {
        var [{ eno, name, collegeName, isApprover, isOrgMan }] = basic;
        return {
            user: { eno, name, isApprover, isOrgMan },
            modules: [true, isApprover, true, true, isOrgMan],
            collegeName,
            grantablePerms
        }
    }
    return null;
}




async function sendLoad(eno) {
    // There are 3 child arrays in the results
    var [
        receiversDepsSrc = null,    //receivers tree [{dno,name,pno,grp},...]
        receiversSrc = null         //receivers [{eno,name,dno},...]
    ] = await run('humanSendLoad', [paraEno(eno)]);

    // if a teacher hasn't any permission, both receviersDepSrc and receiversSrc are null
    // Testing null of one of them to terminate process
    if (!receiversDepsSrc) return;

    // remove "grp" field of none group type departments to save memory
    receiversDepsSrc.forEach(d => { if (d.grp === false) delete d.grp });

    // ({ eno, name }) => ({ eno, name }) only keep eno and name fields, remove dno field
    return assembleStaffGraph(receiversDepsSrc, receiversSrc, ({ eno, name }) => ({ eno, name }));

    /*  result data graph
    [
        {   // this is a "dep" object representing department
            dno:string,
            name:string,
            grp:bool,       // if is not grp, this field doesn't exist
            teachers:[{eno,name},...],
            secs:[
                {
                    dno:string,
                    name:string,
                    teachers:[{eno,name},...]
                },
                ...
            ]
        },
        ...
    ]
    */
}

async function authorizeLoad(eno) {
    // There are 3 child array in the results
    var [
        permDepsSrc = null,         //authorization target tree[{dno,name,pno},...]
        permTeachersSrc = null      //[{eno,name,dno,permission},...]
    ] = await run('humanAuthorizeLoad', [paraEno(eno)]);

    var permDeps = null;
    if (permDepsSrc)
        permDeps = assembleStaffGraph(permDepsSrc, permTeachersSrc, emp => {
            var t = { eno: emp.eno, name: emp.name }
            if (emp.permission && emp.permission > 0) t.perm = emp.permission;
            return t;
        });
    return permDeps;
    /*  result data graph
     [
            {
                dno:string,
                name:string,
                teachers:[{eno,name,perm},...],
                secs:[
                    dno:string,
                    name:string,
                    teachers:[{eno,name,perm},...]
                ]
            },
            ...
        ]
     */ 
}

async function testPermission(eno) {
    var [[{ hasPerm }]] = await run('humanTestPermission', [paraEno(eno)]);
    return hasPerm;
}

async function updatePermission(grantor, ip, identity, perm) {
    const paras = [
        { name: 'grantor', type: SQLTypes.VarChar, value: grantor },
        { name: 'ip', type: SQLTypes.VarChar, value: ip },
        { name: 'identity', type: SQLTypes.Char, value: identity },
        { name: 'perm', type: SQLTypes.Int, value: perm || 0 }
    ];
    //console.log(`grantor:${grantor} ip:${ip} identity:${identity} perm:${perm}`);
    await run('humanAuthorizeUpdatePerm', paras);
}

async function transormReceivers(receivers) {
    const msgId = uuidv1();
    const paras = [
        { name: 'msgId', type: SQLTypes.UniqueIdentifier, value: msgId },
        { name: 'receivers', type: SQLTypes.VarChar, value: receivers }
    ];
    var [{ rowset }] = await run('humanSendTransformReceivers', paras, assmType.ARRAY);
    return { msgId, rowset }
}
async function setStage1MsgGroup(msgId, grpId) {
    const paras = [
        { name: 'msgId', type: SQLTypes.UniqueIdentifier, value: msgId },
        { name: 'grpId', type: SQLTypes.VarChar, value: grpId }
    ]
    await run('humanSendSetMsgGroup', paras);
}

const STAT_TITLES = ['系统发送消息统计', '个人发送信息统计', '部门发送信息统计', '个人接收信息统计'];
async function getStatistics(eno,start,end) {
    var paras = [{ name: 'eno', type: SQLTypes.VarChar, value: eno }];
    if (start) paras.push({ name: 'start', type: SQLTypes.Date, value: start });
    if (end) paras.push({ name: 'end', type: SQLTypes.Date, value: end });
    
    var dataset = await run('humanStatLoad', paras, assmType.ARRAY);
    return dataset.map((data, idx) => (
        {
            title: STAT_TITLES[idx],
            headers: data.headers,
            rows: data.rowset
        })
    )
}


async function historyGetCount(eno) {
    var [[count]] = await run('humanHistoryGetPageCount', [paraEno(eno)]);
    return count;
}
async function historyLoadSent(eno, pageIndex = 0) {
    var paras = [
        paraEno(eno),
        { name: 'pageIndex', type: SQLTypes.Int, value: pageIndex }
    ]
    return await run('humanHistoryGetSent', paras, assmType.ARRAY);
}
async function historyLoadRece(eno, pageIndex = 0) {
    var paras = [
        paraEno(eno),
        { name: 'pageIndex', type: SQLTypes.Int, value: pageIndex }
    ]
    return await run('humanHistoryGetRece', paras, assmType.ARRAY);
}

// ========== exports ============
module.exports = {
    sysLoad,
    sendLoad,
    authorizeLoad,
    testPermission,
    updatePermission,
    getStatistics,
    transormReceivers,
    setStage1MsgGroup,
    historyGetCount,
    historyLoadSent,
    historyLoadRece
}

